package com.example.myapplication.algorithm;

import java.util.Arrays;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

public class filter {
    private static filter INSTANCE;
    public synchronized static filter getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new filter();
        }
        return INSTANCE;
    }
    private static filter INSTANCE1;
    public synchronized static filter getInstance1() {
        if (INSTANCE1 == null) {
            INSTANCE1 = new filter();
        }
        return INSTANCE1;
    }

    /**
     * ECG滤波
     */
    int filter0_len = 3;
    double[] b0 = {0.999132625812721, -1.998265251625443, 0.999132625812721};
    double[] a0 = {1.0, -1.998264499287321, 0.998266003963565};
    public double[] state_signal0 = new double[3];
    public double[] state_result0 = new double[3];
    public double FOut0_ECG = 0;
    public double filter0(double signal)
    {
        int j = 0;
        state_signal0[0] = signal;
        FOut0_ECG = 0;

        for (j = 0; j < filter0_len; j++)
        {
            FOut0_ECG += b0[j] * state_signal0[j];
        }
        for (j = 1; j < filter0_len; j++)
        {
            FOut0_ECG -= a0[j] * state_result0[j - 1];
        }
        for (j = filter0_len - 1; j > 0; j--)
        {
            state_signal0[j] = state_signal0[j - 1];
        }
        for (j = filter0_len - 1; j > 0; j--)
        {
            state_result0[j] = state_result0[j - 1];
        }
        state_result0[0] = FOut0_ECG;
        return FOut0_ECG;
    }

    int filter1_len = 5;
    double[] b1 = {0.965885289744070, -1.301979946640172, 2.370526557928993, -1.301979946640172, 0.965885289744070};
    double[] a1 = {1.0, -1.324580361848915, 2.369362405660521, -1.279379531431428, 0.932934731756612};
    public static double[] state_signal1 = new double[5];
    public static double[] state_result1 = new double[5];
    public static double FOut1_ECG = 0;
    public double filter1(double signal)
    {
        int j = 0;
        state_signal1[0] = signal;
        FOut1_ECG = 0;

        for (j = 0; j < filter1_len; j++)
        {
            FOut1_ECG += b1[j] * state_signal1[j];
        }
        for (j = 1; j < filter1_len; j++)
        {
            FOut1_ECG -= a1[j] * state_result1[j - 1];
        }
        for (j = filter1_len - 1; j > 0; j--)
        {
            state_signal1[j] = state_signal1[j - 1];
        }
        for (j = filter1_len - 1; j > 0; j--)
        {
            state_result1[j] = state_result1[j - 1];
        }
        state_result1[0] = FOut1_ECG;
        return FOut1_ECG;
    }

    int filter2_len = 3;
    double[] b2 = {0.087821281759137, 0.175642563518274, 0.087821281759137};
    double[] a2 = {1.0, -1.004772209703067, 0.356057336739615};
    public static double[] state_signal2 = new double[3];
    public static double[] state_result2 = new double[3];
    public static double FOut2_ECG = 0;
    public double filter2(double signal)
    {
        int j = 0;
        state_signal2[0] = signal;
        FOut2_ECG = 0;

        for (j = 0; j < filter2_len; j++)
        {
            FOut2_ECG += b2[j] * state_signal2[j];
        }
        for (j = 1; j < filter2_len; j++)
        {
            FOut2_ECG -= a2[j] * state_result2[j - 1];
        }
        for (j = filter2_len - 1; j > 0; j--)
        {
            state_signal2[j] = state_signal2[j - 1];
        }
        for (j = filter2_len - 1; j > 0; j--)
        {
            state_result2[j] = state_result2[j - 1];
        }
        state_result2[0] = FOut2_ECG;
        return FOut2_ECG;
    }
    /**
     * ECG带通滤波
     */
    static final int filter3_len = 9;
    double[] b3 = {0.020341578860304,0,-0.081366315441214,0,0.122049473161821,0,-0.081366315441214,0, 0.020341578860304};
    double[] a3 = {1.000000000000000,  -5.466302735155168,  13.064228777810712, -18.028392055417115,  15.878951945012863,  -9.184407175091327,   3.392535546629019,
            -0.726948933555153,   0.070334637496954};
    public static double[] state_signal3 = new double[filter3_len];
    public static double[] state_result3 = new double[filter3_len];
    public static double FOut3_ECG = 0;
    public double filter_ecg(double signal)
    {
        int j = 0;
        state_signal3[0] = signal;
        FOut3_ECG = 0;

        for (j = 0; j < filter3_len; j++)
        {
            FOut3_ECG += b3[j] * state_signal3[j];
        }
        for (j = 1; j < filter3_len; j++)
        {
            FOut3_ECG -= a3[j] * state_result3[j - 1];
        }
        for (j = filter3_len - 1; j > 0; j--)
        {
            state_signal3[j] = state_signal3[j - 1];
        }
        for (j = filter3_len - 1; j > 0; j--)
        {
            state_result3[j] = state_result3[j - 1];
        }
        state_result3[0] = FOut3_ECG;
        return FOut3_ECG;
    }

    /**
     * PPG滤波
     */
    static final int filter4_len = 9;
    double[] b4 = {0.001543826121648,                   0,  -0.006175304486592,                   0,   0.009262956729888,                   0,  -0.006175304486592,                  0,   0.001543826121648};
    double[] a4 = {1.000000000000000,  -6.734876145994429,  19.954104229569666, -33.995303211026616,  36.446167466404887, -25.187204447018711,  10.958815931913943, -2.744652561473047,   0.302948975942265};
//    double[] b4 = {0.002186484696690,                   0,  -0.008745938786761,                   0,   0.013118908180142,                   0,  -0.008745938786761,                   0,   0.002186484696690};
//    double[] a4 = {1.000000000000000,  -6.695310167750643,  19.657792517619441, -33.089113466318850,  34.951747100047427, -23.735550264841272,  10.121929828093382,  -2.478213858819410,   0.266718311973417};

    public static double[] state_signal4 = new double[filter4_len];
    public static double[] state_result4 = new double[filter4_len];
    public static double FOut4_ECG = 0;
    public double filter_ppg(double signal)
    {
        int j = 0;
        state_signal4[0] = signal;
        FOut4_ECG = 0;

        for (j = 0; j < filter4_len; j++)
        {
            FOut4_ECG += b4[j] * state_signal4[j];
        }
        for (j = 1; j < filter4_len; j++)
        {
            FOut4_ECG -= a4[j] * state_result4[j - 1];
        }
        for (j = filter4_len - 1; j > 0; j--)
        {
            state_signal4[j] = state_signal4[j - 1];
        }
        for (j = filter4_len - 1; j > 0; j--)
        {
            state_result4[j] = state_result4[j - 1];
        }
        state_result4[0] = FOut4_ECG;
        return FOut4_ECG;
    }
    private double[] mirrorPadding(double[] x, int n) {
        int len = x.length;
        double[] extended = new double[len + 2 * n];

        // 左端延拓（三阶外推）
        for (int i = 0; i < n; i++) {
            extended[n-1-i] = 3*x[0] - 3*x[1] + x[2];
        }

        System.arraycopy(x, 0, extended, n, len);

        // 右端延拓
        for (int i = 0; i < n; i++) {
            extended[n + len + i] = 3*x[len-1] - 3*x[len-2] + x[len-3];
        }
        return extended;
    }
    public double[] filtfilt_ppg(double[] signal) {
        // 信号延拓
        int n = signal.length;
        double[] y = new double[n];
        // 正向滤波
        resetStates();
        for (int i = 0; i < y.length; i++) {
            y[i] = filter_ppg(signal[i]);
        }
        // 反向滤波
        resetStates();
        for (int i = y.length - 1; i >= 0; i--) {
            y[i] = filter_ppg(y[i]);
        }
        return Arrays.copyOfRange(y, 400, 400 + 400);// 返回中间400个点
    }
    // 重置滤波器状态
    private void resetStates() {
        state_signal4 = new double[filter4_len];
        state_result4 = new double[filter4_len];
        FOut4_ECG = 0;
    }
    private Queue<Double> window = new ConcurrentLinkedQueue<>();; // 窗口队列
    public int windowIndex = 0; // 窗口索引
    public void add(double newValue) {
        // 如果窗口已满，移除最旧的数据
        if (window.size() >= 1200) {
            window.poll();
        }
        // 添加新数据并更新和
        window.add(newValue);
    }
    public double[] getWindow() {
        return window.stream().mapToDouble(Double::doubleValue).toArray();
    }
    public boolean isWindowFull() {
        return window.size() >= 1200;
    }

    /**
     * 呼吸滤波
     */
    static final int filter5_len = 3;
    double[] b5 = {0.028129622080948,                   0,  -0.028129622080948};
    double[] a5 = {1.000000000000000,  -1.941747747252976,   0.943740755838104};
    public static double[] state_signal5 = new double[filter5_len];
    public static double[] state_result5 = new double[filter5_len];
    public static double FOut5_ECG = 0;
    public double filter_breathe(double signal)
    {
        int j = 0;
        state_signal5[0] = signal;
        FOut5_ECG = 0;

        for (j = 0; j < filter5_len; j++)
        {
            FOut5_ECG += b5[j] * state_signal5[j];
        }
        for (j = 1; j < filter5_len; j++)
        {
            FOut5_ECG -= a5[j] * state_result5[j - 1];
        }
        for (j = filter5_len - 1; j > 0; j--)
        {
            state_signal5[j] = state_signal5[j - 1];
        }
        for (j = filter5_len - 1; j > 0; j--)
        {
            state_result5[j] = state_result5[j - 1];
        }
        state_result5[0] = FOut5_ECG;
        return FOut5_ECG;
    }

    public int filtfilt_breathe_len = 38 * 12; // 呼吸滤波长度
    public double[] filtfilt_breathe(double[] signal) {
        int n = signal.length;
        double[] y = new double[n];
        // 正向滤波
        state_signal5 = new double[filter5_len];
        state_result5 = new double[filter5_len];
        FOut5_ECG = 0;
        for (int i = 0; i < n; i++) {
            y[i] = filter_breathe(signal[i]);
        }
        // 反向滤波
        state_signal5 = new double[filter5_len];
        state_result5 = new double[filter5_len];
        FOut5_ECG = 0;
        for (int i = n - 1; i >= 0; i--) {
            y[i] = filter_breathe(y[i]);
        }
        return Arrays.copyOfRange(y, filtfilt_breathe_len, filtfilt_breathe_len * 2);// 返回中间400个点;
    }
    private Queue<Double> RespWindow = new ConcurrentLinkedQueue<>();; // 窗口队列
    public int RespWindowIndex = 0; // 窗口索引
    public void addResp(double newValue) {
        // 如果窗口已满，移除最旧的数据
        if (RespWindow.size() >= filtfilt_breathe_len * 3) {
            RespWindow.poll();
        }
        // 添加新数据并更新和
        RespWindow.add(newValue);
    }
    public double[] getRespWindow() {
        return RespWindow.stream().mapToDouble(Double::doubleValue).toArray();
    }
    public boolean isRespWindowFull() {
        return RespWindow.size() >= filtfilt_breathe_len * 3;
    }
}
